<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>DY练习</title>
    <script type="text/javascript" type="module" defer></script>
  </head>

  <body>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        /**平滑滚动*/
        scroll-behavior: smooth;
        /* writing-mode: vertical-lr; */
        touch-action: none;
      }
      .parallelogram {
        position: relative;
        width: 160px;
        height: 64px;
      }

      .parallelogram::before {
        content: '';
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        background: #03f463;
        transform: skewX(15deg);
        user-select: none;
        pointer-events: none;
        cursor: pointer;
      }
      .wrapper {
        width: 40%;
        background: #03f463;
        background-clip: padding-box;
        padding: 20px;
        box-sizing: border-box;
        transition: all 0.5s;
      }
      .wrapper:hover {
        transform-origin: 0 0;
        transform: scale(1.1, 1);
        width: 50%;
        /* width: 60%; */
      }
      .inner {
        width: 100%;
        background: #39644a;
        /* height: 200px; */
        box-sizing: border-box;
        padding-bottom: 50%;
        /*元素pading margin 的百分比 是基于父元素的宽度的百分比
                css3 translate 是基础本身
              */
      }

      a[target='_blank'] {
        /* 从下到上，从蓝色开始渐变、到高度40%位置是绿色渐变开始、最后以红色结束 */
        /* background-image: linear-gradient(90deg, blue 10%, green 40%, red 50%); */
        background: -webkit-linear-gradient(315deg, #42d392 25%, #647eff);
        background-clip: text;
        -webkit-background-clip: text;
        color: transparent;
        font-weight: bold;
        font-size: 35px;
        display: flex;
        width: 100%;
        justify-content: center;
        align-items: center;
        writing-mode: vertical-lr;
        letter-spacing: 3px;
      }
      .qiu {
        width: 50px;
        height: 50px;
        margin: 20px;
        border: 10px solid red;
        /* position: absolute; */
        /* background-color: red; */
        border-radius: 50%;
        /* transition: all 0.3s; */
        /* transition-timing-function: linear; */
      }
      .container {
        width: 500px;
        height: 350px;
        border: 1px solid;
        margin: 100px auto;
        overflow: hidden;
        position: relative;
        box-sizing: content-box;
      }
      .caul {
        display: flex;
        width: 100%;
        height: 100%;
        transition: all 0.5s;
      }

      .item {
        width: 500px;
        height: 350px;
      }
      .caul div img {
        width: 500px;
        height: 350px;
      }
      .dian {
        position: absolute;
        bottom: 10px;
        display: flex;
        gap: 10px;
        left: 50%;
        transform: translateX(-50%);
      }
      .dian span {
        width: 30px;
        height: 30px;
        background-color: red;
        border-radius: 50%;
        cursor: pointer;
      }
      .dian span.active {
        background-color: rgb(13, 38, 13);
      }
      .right,
      .left {
        position: absolute;
        background: red;
        top: 50%;
        border-radius: 8px;
        padding: 3px;
        cursor: pointer;
      }
      .right {
        right: 0;
      }
      .test {
        width: 100px;
        height: 100px;
        background-color: green;
      }

      .test:hover:active {
        background-color: black;
      }
    </style>

    <div class="test">Lorem ipsum dolor sit amet.</div>
    <div class="wrapper">
      <div class="inner">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas ea minus quasi nobis sit perspiciatis ab eveniet
        quaerat voluptatibus cum?
      </div>
      <p>这是文字</p>
    </div>

    <div class="qiu"></div>
    <!-- dataset.index -->
    <a target="_blank" data-index="77">无缝轮播</a>
    <div class="container">
      <div class="caul">
        <div class="item item1">
          123
          <img
            src="https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
            alt=""
            fetchpriority="high"
            importance="high"
          />
        </div>
        <div class="item item2">
          222
          <img
            src="https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80"
            alt=""
            fetchpriority="high"
            importance="high"
          />
        </div>
        <div class="item item3">
          333
          <img
            src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80"
            alt=""
            fetchpriority="high"
          />
        </div>
        <div class="item item4">
          444
          <img
            src="https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80"
            alt=""
            fetchpriority="high"
          />
        </div>
        <!-- 'https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80' -->
      </div>
      <div class="dian">
        <span class="active"></span>
        <span></span>
        <span></span>
        <span></span>
      </div>
      <span class="left">&lt;</span>
      <span class="right">&gt;</span>
    </div>

    <!-- 响应式图片 -->
    <!-- <picture>
      <source
        type="image/webp"
        srcset="homepage-person@desktop.png, homepage-person@desktop-2x.png 2x"
        media="(min-width: 990px)"
      />
      <source
        type="image/svg+xml"
        srcset="homepage-person@tablet.png, homepage-person@tablet-2x.png 2x"
        media="(min-width: 750px)"
      />
      <img
        srcset="homepage-person@mobile.png, homepage-person@mobile-2x.png 2x"
        alt="Shopify Merchant, Corrine Anestopoulos"
      />
    </picture> -->
    <!-- 上面代码中，<source>标签的media属性给出屏幕尺寸的适配条件，每个条件都用srcset属性，再给出两种像素密度的图像 URL。 -->
    <!-- 除了响应式图像，<picture>标签还可以用来选择不同格式的图像。比如，如果当前浏览器支持 Webp 格式，就加载这种格式的图像，否则加载 PNG 图像。 -->
    <style>
      :root {
        /* font-size: calc(100vw / 1920);
         */
        /* font-size: calc(16px * 0.625); */

        font-size: 62.5%;
        --home-background: #03f463;
        scroll-behavior: smooth;
      }
      .flex {
        display: flex;
        width: 100%;
        height: 500px;
      }
      .flex-item {
        flex: 1;
      }
      .flex-item-active {
        flex: 5;
      }
      .flex-item-active2 {
        flex: 2;
      }
    </style>
    <div class="flex">
      <div class="flex-item flex-item-active">78978978</div>
      <div class="flex-item flex-item-active2">54654</div>
      <div class="flex-item">21</div>
      <div class="flex-item">312</div>
      <div class="flex-item">312</div>
    </div>

    <img
      loading="lazy"
      draggable="false"
      width="600"
      height="400"
      src="https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80"
      alt=""
      id="im"
    />
    <!-- <table cellspacing="0" bgcolor="green" width="500" height="200" border="0" cellpadding="0">
      <caption>
        <h3>课程表</h3>
      </caption>
      <tr bgcolor="white">
        <th>789</th>
        <th>789</th>
        <th>789</th>
        <th>789</th>
      </tr>
      <tr bgcolor="white">
        <td>123</td>
        <td>123</td>
        <td>123</td>
        <td>123</td>
      </tr>
      <tr bgcolor="white">
        <td>123</td>
        <td>123</td>
        <td>123</td>
        <td>123</td>
      </tr>
      <tr bgcolor="white">
        <td>123</td>
        <td>123</td>
        <td>123</td>
        <td>123</td>
      </tr>
      <tr bgcolor="white">
        <td>123</td>
        <td>123</td>
        <td>123</td>
        <td>123</td>
      </tr>
    </table> -->
    <script>
      let obj = {
        push: Array.prototype.push,
      };
      // obj.push(77);
      // console.log('obj ', obj);
    </script>

    <script src="./carousel.js"></script>

    <script type="module">
      // console.log(obj);
      // console.log('  document.q', document.querySelector('.inner').textContent);
      // const reg = new RegExp(word,'g');
      // let resf = document.querySelector('.inner').textContent.replace(reg, (item) => {
      //   console.log('item', item);
      //   return 99;
      // });

      // console.log('resf', resf);
      // document.querySelector('.wrapper').onclick = function () {
      //   console.log('wrapper');
      // };
      // 禁用鼠标滚轮事件
      document.addEventListener(
        'wheel',
        (event) => {
          event.preventDefault();
        },
        {
          // 代表告诉了浏览器该监听事件内部不会调用e.preventDefault()来阻止默认行为
          passive: false, //声明wheel事件里是否不调用 preventDefault()，可以减少系统默认行为的等待
        }
      );

      // 鼠标右键事件
      // document.addEventListener('contextmenu', (event) => {
      //   event.preventDefault();
      //   console.log('contextmenu', event);
      // });

      // history.pushState(stateObject, "My title", "baz.html");
      // .history.replaceState(stateObject, "My title", "baz.html");

      //  window.addEventListener("popstate", (event) => {
      //  let state = event.state;
      //  if (state) { // 第一个页面加载时状态是 null
      //  processState(state);
      //  }
      // });

      // const n = new Notification('I will close in 1000ms');
      // setTimeout(() => n.close(), 2000);

      // try {
      //   console.log('try');

      //   a;
      // } catch {}
      // console.log('finally789');
      const worker = new Worker('webwork.js', {
        name: 'myWorker',
        type: 'module',
      });
      worker.postMessage([789789]);
      worker.addEventListener('message', function (event) {
        console.log('接收worker线程的消息 ', event.data);
      });
      worker.addEventListener('error', function (event) {
        console.log('worker线程发生了错误 ', error);
      });

      // // 主线程 关闭 Worker
      // worker.terminate();
      // // Worker 线程 关闭 Worker
      // self.close();

      const io = new IntersectionObserver(
        (ev) => {
          ev.forEach((item) => {
            /*
             * item.time发生相交到相应的时间，毫秒
             * item.rootBounds：根元素矩形区域的信息，如果没有设置根元素则返回 null，图中蓝色部分区域。
             * item.boundingClientRect：目标元素的矩形区域的信息，图中黑色边框的区域。
             * item.intersectionRect：目标元素与视口（或根元素）的交叉区域的信息，图中蓝色方块和粉红色方块相交的区域。
             * item.isIntersecting：目标元素与根元素是否相交
             * item.intersectionRatio：目标元素与视口（或根元素）的相交比例。
             * item.target：目标元素，图中黑色边框的部分。
             */
            // console.log('item', item);
            io.unobserve(item.target);
          });
        },
        {
          // threshold: 0.5, //目标元素与视窗重叠的值（0~1）
          root: null, // 目标视窗即目标元素的父元素，如果没有提供，则默认body元素(视口)
          // root,
          // DOM元素，但默认值为null，也就是视口区域
          // 表示监听的可视区域为整个视口，也就是浏览器的可视区域
          // 如果设置了DOM元素，那么视口就变为该元素（即，就算元素在屏幕的可视区域，但是不在该DOM元素的可视区域，仍然不会触发可视性变化）

          // rootMargin (距离多少外边距就触发)
          // 类似于css的margin属性，可以设置四个属性。
          // 该属性默认值为`0px 0px 100px 0px`，如果设置之后，会影响触发回调的时间

          // takeRecords
          // 该属性，目前没有找到是干嘛的，返回一个数组，而且一直为空数组

          // thresholds
          // Array
          // 默认值为[0]，
          // 当元素的进入可视区域的百分比达到这个参数的设置值得时候
          // 就会触发IntersectionObserver实例中的callback的回调函数
          // 具体后面再看啦
        }
      );
      io.observe(document.querySelector('#im'));
      // Stop observing threshold events on all target elements.
      // 停止所有的监听
      // observer.disconnect();

      const log = console.log.bind(document);
      let stss = '10000000000';
      const newStss = stss.replace(/(?=\B(\d{3})+$)/g, ','); //把金额以三位分割
      // Number.toLocaleString()
      // log('newStss', newStss);

      //获取地址栏参数
      function getUrlSearch(name) {
        const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
        const result = window.location.search.substr(1).match(reg);
        if (result) return unescape(r[2]);
        return null;
      }

      function group2(array, subNum) {
        console.log(array);
        let newArray = [];
        for (let i = 0; i < array.length; i++) {
          // newArray.push(array.slice(i, (i += subNum)));
          newArray.push(array.slice(i, i + subNum));
          // i += subNum - 1;
          i = i + subNum - 1;
          // newArray.push(array.slice(i * subNum, (i + 1) * subNum));
        }
        return newArray;
        // return newArray.filter((item) => item.length);
      }
      // console.log(group2([1, 2, 3, 45, 7, 8, 9, 75, 5, 4], 3));
      // for (let index = '100'.length - 1; index >= 0; index--) {
      //   console.log(index);3
      // }
      // for (let index = 0, len = array.length; index < len; index++) {
      //   const element = array[index];
      // }

      // let o = { age: 20, items: { uid: 999 } };
      // function objFn(obj) {
      //   obj = { value: 777 };
      //   obj.name = 'test';
      //   console.log('obj', obj);
      // }
      // objFn(o);
      // console.log('lo', o);

      // function parsePath(path) {
      //   const segments = path.split('.');
      //   console.log(segments);
      //   return function (vm) {
      //     for (let i = 0; i < segments.length; i++) {
      //       if (!vm) return;
      //       console.log(vm);

      //       vm = vm[segments[i]];
      //       console.log(vm);
      //     }
      //     console.log(vm);
      //     return vm;
      //   };
      // }
      // const ruct = parsePath('a.b.c');

      // ruct({
      //   a: {
      //     b: {
      //       c: 789,
      //     },
      //   },
      // });

      // let vm = 'agas.gs.com';
      // let vmArr = vm.split('.');

      // console.log('vmArr', vmArr[vmArr.length - 1]);
      // console.log(vm.slice(-3));

      // const div = document.getElementById('hd');
      // function handle() {
      //   let i = 0;
      //   (function run() {
      //     console.log(i);
      //     div.innerHTML = i;
      //     div.style.width = i + '%';
      //     if (++i <= 100) setTimeout(run, 10);
      //   })();
      // }
      // handle();

      // async function load() {
      //   for (let i = 0; i <= 100; i++) {
      //     await new Promise((resolve) => {
      //       setTimeout(() => {
      //         resolve();
      //       }, 100);
      //     });
      //     div.innerHTML = i;
      //     div.style.width = i + '%';
      //   }
      // }
      // load();
      // async function sleep() {
      //   return new Promise(resolve => {
      //     setTimeout(resolve, 100)
      //   })
      // }
      // async function load() {
      //   for (let i = 0; i <= 100; i++) {
      //     div.innerHTML = i
      //     div.style.width = i + '%'
      //     await sleep()
      //   }
      // }
      // load()
      // window.onload=function(){
      // 	onResize()
      // }
      // window.onresize=function(){
      //   onResize()
      // }

      // function onResize() {

      // window.onresize=function(){
      // 	const html= document.documentElement
      // 	let oWidth = document.body.clientWidth || document.documentElement.clientWidth;
      // 	let num=20
      // 	console.log(html.style.fontSize=oWidth/num +'px');
      // }

      // let str = 'abcdef'
      // console.log(str.charAt(2));
      // console.log(str[2]);
      // console.log([...str].reverse().join(''));反转字符串

      // let totel = +str
      // console.log(totel);
      // let num =456
      // console.log(num);
      // let res=num+''
      // console.log(res);

      //---------------------------------------

      // //防抖
      // function name(fn, wait = 150) {
      //   let timer = null
      //   if (timer) clearTimeout(timer)
      //   return function (...arg) {
      //     timer = setTimeout(() => {
      //       fn.apply(this, arg)
      //     }, wait)
      //   }
      // }

      // function debounce(fn, delay = 150) {
      //   let timeout = null
      //   return function (...args) {
      //     if (timeout) clearTimeout(timeout)
      //     timeout = setTimeout(() => {
      //       fn.apply(this, arg)
      //     }, delay)
      //   }
      // }

      // //----------------------------------------------

      // //节流1
      // function nn(fn, wait) {
      //   let timer = null
      //   if (!timer) {
      //     return function (...arg) {
      //       timer = setTimeout(() => {
      //         fn.apply(this, arg)
      //         timer = null
      //       }, wait)
      //     }
      //   }
      // }

      // function nnn(fn, wait) {
      //   let flag = true
      //   if (!flag) return
      //   flag = false
      //   return function (...arg) {
      //     setTimeout(() => {
      //       fn.apply(this, arg)
      //       flag = true
      //     }, wait)
      //   }
      // }

      // console.log(String.fromCharCode(97));
      // console.log('ba'.charAt(0));
      // console.log('ba'.substring(0, 1));
      // console.log('ba'.slice(0, 1));
      // console.log('ba'.substr(0, 1));
      // console.log('ba'.charCodeAt(0));

      //----------------------------------------------------------

      //防抖debounce代码：
      // function debounce(fn, delay = 150) {
      //   let timeout = null; // 创建一个标记用来存放定时器的返回值
      //   return function (...args) {
      //     // 每当用户输入的时候把前一个 setTimeout clear 掉
      //     if (timeout) clearTimeout(timeout);
      //     // 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发，就不会执行 fn 函数
      //     timeout = setTimeout(() => {
      //       fn.apply(this, arg);
      //     }, delay);
      //   };
      // }

      //节流方案一
      // function throttle(fn, delay = 150) {
      //   let canRun = true; // 通过闭包保存一个标记
      //   return function (...arg) {
      //     // 在函数开头判断标记是否为true，不为true则return
      //     if (!canRun) return;
      //     // 立即设置为false
      //     canRun = false;
      //     // 将外部传入的函数的执行放在setTimeout中
      //     setTimeout(() => {
      //       // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
      //       // 当定时器没有执行的时候标记永远是false，在开头被return掉
      //       fn.apply(this, arg);
      //       canRun = true;
      //     }, delay);
      //   };
      // }

      // // 定时器节流方案二
      // function throttle(fn, wait = 150) {
      //   let timer = null;
      //   return function (...args) {
      //     //var context = this;
      //     //var args = arguments;
      //     if (!timer) {
      //       timer = setTimeout(function () {
      //         fn.apply(this, args);
      //         timer = null;
      //       }, wait)
      //     }
      //   }
      // }
      // // 深拷贝拷贝对象封装函数 (递归)
      // function deepCopy(newobj, oldobj) {
      //   for (var k in oldobj) {
      //     // 判断我们的属性值属于那种数据类型
      //     // 1. 获取属性值  oldobj[k]
      //     var item = oldobj[k];
      //     // 2. 判断这个值是否是数组
      //     if (item instanceof Array) {
      //       newobj[k] = [];
      //       deepCopy(newobj[k], item)
      //     } else if (item instanceof Object) {
      //       // 3. 判断这个值是否是对象
      //       newobj[k] = {};
      //       deepCopy(newobj[k], item)
      //     } else {
      //       // 4. 属于简单数据类型
      //       newobj[k] = item;
      //     }
      //   }
      // }

      // //时间格式化
      function formatDate(date, fmt) {
        if (/(y+)/.test(fmt)) {
          fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
        }
        let o = {
          'M+': date.getMonth() + 1,
          'd+': date.getDate(),
          'h+': date.getHours(),
          'm+': date.getMinutes(),
          's+': date.getSeconds(),
        };
        for (let k in o) {
          if (new RegExp(`(${k})`).test(fmt)) {
            let str = o[k] + '';
            fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? str : padLeftZero(str));
          }
        }
        return fmt;
      }
      function padLeftZero(str) {
        return ('00' + str).substr(str.length);
      }

      // let hd = {};
      // //  Object.prototype.show =function () {
      // //    console.log(123);
      // //  }
      // //  hd.show()
      // console.log(Object.prototype.__proto__ === null);

      // const lessons = [
      //   {
      //     title: "媒体查询响应式布局",
      //     category: "css"
      //   },
      //   {
      //     title: "FLEX 弹性盒模型",
      //     category: "css"
      //   },
      //   {
      //     title: "MYSQL多表查询随意操作",
      //     category: "mysql"
      //   }
      // ];
      // let lessonObj = lessons.reduce((obj, cur, index) => {
      //   obj[`${cur["category"]}-${index}`] = cur;
      //   return obj;
      // }, {});
      // console.log(lessonObj); //{css-0: {…}, css-1: {…}, mysql-2: {…}}

      // console.log(lessonObj["css-0"]); //{title: "媒体查询响应式布局", category: "css"}

      // let rr = 'key=vals'.match(/^(.+)=(.+)$/); // [原始值，匹配到的值，index]
      // console.log(rr);
      // console.log(rr['input']);
      // console.dir(RegExp.$1);
      // console.dir(RegExp.$2);
      // console.dir(RegExp.$_);
      // console.dir(RegExp.input);

      // var name = 1;
      // function test() {
      //   var name = 2;
      //   console.log(this.name);
      //   return function inner() {
      //     console.log(name);
      //   };
      // }
      // test();
      // test()();
      // var b = {
      //   name: 3,
      // };
      // b.test = test;
      // b.test();
      // var c = b.test;
      // c();
      // new test();

      class Stack {
        constructor() {
          this.arr = [];
        }
        in(value) {
          // 你的代码
          this.arr.push(value);
        }
        out() {
          // 你的代码
          return this.arr.pop();
        }
        top() {
          // 你的代码
          // return this.arr[this.arr.length - 1];
          return this.arr.at(-1);
        }
        size() {
          // 你的代码
          return this.arr.length;
        }
      }

      // 要求当执行下列代码时，能输出预期的结果
      // const stack = new Stack();
      // stack.in('x');
      // stack.in('y');
      // stack.in('z');
      // console.log(stack);
      // console.log(stack.top()); // 输出 'z'
      // console.log(stack.size()); // 输出 3
      // console.log(stack.out()); // 输出 'z'
      // console.log(stack.top()); // 输出 'y'
      // console.log(stack.size()); // 输出 2

      // 输入 array = [1,5,2,3,2,5,4] 输出 [1, 5, 2, 3, 4]
      function unique(array = [1, 5, 2, 3, 2, 5, 4]) {
        // 在这里实现
        return array.filter((item, index) => array.indexOf(item) === index);
      }
      // unique();
      const filterNonUnique = (array) => {
        return array.filter((i) => array.indexOf(i) === array.lastIndexOf(i));
      };
      const uniqueElements = (array) => {
        return [...new Set(array)];
      };

      function fetchData(callback) {
        setTimeout(() => {
          callback('我是返回的数据');
        }, 5000);
      }

      // 实现下面的函数
      function promiseFecth() {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve('我是返回的数据');
          }, 5000);
        });
      }
      // promiseFecth().then((res) => {
      //   console.log(res); // 我是返回的数据
      // });

      const address = [
        {
          id: 1,
          name: '北京市',
          children: [
            { id: 11, name: '海淀区', children: [{ id: 111, name: '中关村' }] },
            { id: 12, name: '朝阳区' },
          ],
        },
        { id: 2, name: '河北省' },
      ];
      // 输入：getNameById(address, 2)，输出："河北省"
      // 输入：getNameById(address, 111)，输出："中关村"
      // 输入：getNameById(address, 32)，输出："" （未查找到，输出空字符串）
      function getNameById(address, id) {
        let res = '';
        for (const item of address) {
          if (item.children?.length) {
            res = getNameById(item.children, id);
          } else {
            if (item.id === id) {
              res = item.name;
              break;
            }
          }
        }
        return res;
      }

      // console.log(getNameById(address, 2));
      // console.log(getNameById(address, 111));
      // console.log(getNameById(address, 32));

      class Pro {
        status = 'pending';
        value = null;
        callbacks = [];
        constructor(executor) {
          try {
            executor(this.resolve.bind(this), this.reject.bind(this));
          } catch (error) {
            this.reject(error);
          }
        }
        resolve(value) {
          if (this.status === 'pending') {
            this.status = 'resolve';
            this.value = value;
            this.callbacks.map((item) => {
              setTimeout(() => {
                item.onResove && item.onResove();
              });
            });
          }
        }
        reject(value) {
          if (this.status === 'pending') {
            this.status = 'reject';
            this.value = value;
            this.callbacks.map((item) => {
              setTimeout(() => {
                item.onReject && item.onReject();
              });
            });
          }
        }

        then(onResove, onReject) {
          const onResoveOrOnReject = (onResoveOrOnReject) => {
            let result = onResoveOrOnReject(this.value);
            if (result === proRes) {
              throw new Error('不能相等');
            }
            try {
              if (result instanceof Pro) {
                result.then(resolve, reject);
              } else {
                resolve(result);
              }
            } catch (error) {
              reject(error);
            }
          };
          const proRes = new Pro((resolve, reject) => {
            if (typeof resolve !== 'function') {
              resolve = (value) => value;
            }
            if (typeof reject !== 'function') {
              resolve = (value) => value;
            }
            if (this.status === 'resolve') {
              setTimeout(() => {
                onResoveOrOnReject(onResove);
              });
            }
            if (this.status === 'reject') {
              setTimeout(() => {
                onResoveOrOnReject(onReject);
              });
            }
            if (this.status === 'pending') {
              this.callbacks.push({
                onResove: () => {
                  onResoveOrOnReject(onResove);
                },
                onReject: () => {
                  onResoveOrOnReject(onReject);
                },
              });
            }
          });
          return proRes;
        }
        catch(onRreject) {
          return this.then(undefined, onRreject);
        }

        static resolve(value) {
          return new Pro((resolve, reject) => {
            try {
              if (value instanceof Pro) {
                value.then(resolve, reject);
              } else {
                resolve(value);
              }
            } catch (error) {
              reject(error);
            }
          });
        }

        static reject(value) {
          return new Pro((resolve, reject) => {
            reject(value);
          });
        }

        static race(value) {
          return new Pro((resolve, reject) => {
            value.forEach((item) => {
              item.then(resolve, reject);
            });
          });
        }

        static all(proArr) {
          let arr = [];
          return new Pro((resolve, reject) => {
            proArr.forEach((item, index) => {
              item.then(
                (v) => {
                  arr[index] = v;
                  if (arr.length === proArr.length) {
                    resolve(arr);
                  }
                },
                (r) => {
                  reject(r);
                }
              );
            });
          });
        }
      }

      // var a = { n: 1 };
      // b = a;
      // a.x = a = { n: 2 };

      // console.log(a.x);
      // console.log(b.x);
      // function name1() {
      //   var a = (b = 10);
      //   console.log(a, b);
      // }
      // name1();
      // console.log('b', b);
      // console.log('a', typeof a === 'undefined');
    </script>
  </body>
</html>
